package com.demo.controller;

import com.demo.function.skywalking.SkywalkingService;
import com.demo.model.dto.AlarmMessage;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 配合Skywalking功能使用的控制层
 * @author cyj
 */
@Slf4j
@RestController
public class SkywalkingController {

    ExecutorService executorService = Executors.newFixedThreadPool(10);

    @Value("${spring.mail.username}")
    private String from;

    @Resource
    private JavaMailSender sender;
    @Resource
    private SkywalkingService skywalkingService;

    /**
     * 测试skywalking性能剖析功能
     * 性能剖析文档：https://skywalking.apache.org/zh/2020-03-23-using-profiling-to-fix-the-blind-spot-of-distributed-tracing/
     *
     * 设置sleep时间长一点，可以触发skywalking告警功能
     * @return 布尔类型
     */
    @SneakyThrows
    @GetMapping("/skywalking/pref")
    public Boolean pref() {

        final CountDownLatch countDownLatch= new CountDownLatch(2);
        try {
            executorService.submit(new Task(countDownLatch));
            executorService.submit(new Task(countDownLatch));

            Thread.sleep(1500);
        } finally {
            countDownLatch.countDown();
        }
        return Boolean.TRUE;
    }

    private static class Task implements Runnable {

        private final CountDownLatch countDownLatch;

        public Task(CountDownLatch countDownLatch) {
            this.countDownLatch = countDownLatch;
        }

        @SneakyThrows
        @Override
        public void run() {
            log.info("线程名 = " + Thread.currentThread().getName());
            Thread.sleep(500);
            log.info("await结束");
            countDownLatch.countDown();
        }
    }

    /**
     * 接收skywalking服务的告警通知并发送至邮箱
     * skywalking告警参考文档：
     *  https://www.jianshu.com/p/5cc42569af6f
     */
    @PostMapping("/skywalking/alarm")
    public void alarm(@RequestBody List<AlarmMessage> alarmList) {
        SimpleMailMessage message = new SimpleMailMessage();
        // 发送者邮箱
        message.setFrom(from);
        // 接收者邮箱
        message.setTo(from);
        // 主题
        message.setSubject("告警邮件");
        String content = getContent(alarmList);
        // 邮件内容
        message.setText(content);
        sender.send(message);
        log.info("告警邮件已发送...");
    }

    private String getContent(List<AlarmMessage> alarmList) {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        StringBuilder sb = new StringBuilder();
        for (AlarmMessage dto : alarmList) {
            sb.append("scopeId: ").append(dto.getScopeId())
                    .append("\nscope: ").append(dto.getScope())
                    .append("\n目标 Scope 的实体名称: ").append(dto.getName())
                    .append("\nScope 实体的 ID: ").append(dto.getId0())
                    .append("\nid1: ").append(dto.getId1())
                    .append("\n告警规则名称: ").append(dto.getRuleName())
                    .append("\n告警消息内容: ").append(dto.getAlarmMessage())
                    .append("\n告警时间: ").append(format.format(new Date(dto.getStartTime())))
                    .append("\n\n---------------\n\n");
        }

        return sb.toString();
    }

    /**
     * 使用Spring注解@Async可以打印trace id
     * @return 返回布尔类型
     */
    @GetMapping("/skywalking/spring/thread/trace")
    public Boolean springThreadTrace() {
        log.info("开始执行异步线程");
        skywalkingService.springAsync();
        return Boolean.TRUE;
    }

    /**
     * 采用java 8 CompletableFuture执行异步线程，无法打印trace id
     * @return 返回布尔类型
     */
    @GetMapping("/skywalking/completable/future/thread/trace")
    public Boolean completableFutureThreadTrace() {
        log.info("开始执行异步线程");
        CompletableFuture.supplyAsync(() -> skywalkingService.completableFuture());
        return Boolean.TRUE;
    }
}
